//-----------------------------------------------------------------------------
// Bend2D - Physics Engine
// Roberto Bender <beto.bender@gmail.com>
// Description: 
// Date: 09/03/2010
//-----------------------------------------------------------------------------
#include "point.h"
#include "bmath.h"
#include <sstream>

using namespace bend2d;
using namespace std;

void Point::CalculateFromXY()
{
    m_Mag = Math::Sqrt(m_X*m_X + m_Y*m_Y);
    
    if(m_Y == 0 && m_X == 0)
        m_Angle = 0;
    else if(m_Y == 0 && m_X > 0)
        m_Angle = 0;
    else if(m_Y == 0 && m_Y < 0)
        m_Angle = 180;
    else
        m_Angle = Math::ArcTg(m_Y/m_X);
    
    if(m_X < 0) m_Angle += 180;
}

void Point::CalculateFromMagAngle()
{
    if(m_Mag == 0)
    {
        m_X = 0;
        m_Y = 0;
    }    
    else
    {
        m_X = m_Mag * Math::Cos(m_Angle);
        m_Y = m_Mag * Math::Sin(m_Angle);
    }
}

Point::Point() : 
    m_X(0),
    m_Y(0),
    m_Mag(0)
{
}

Point::Point(double x, double y) :
    m_X(x),
    m_Y(y)
{
    CalculateFromXY();
}

Point::Point(double mag) :
    m_Mag(mag)
{
    m_X = mag;
    m_Y = 0;
}

Point::Point(double mag, const Angle& angle) :
    m_Mag(mag),
    m_Angle(angle)
{
    CalculateFromMagAngle();
}

double Point::GetX() const
{
    return m_X;
}

double Point::GetY() const
{
    return m_Y;
}

double Point::GetMag() const
{
    return m_Mag;
}

const Angle& Point::GetAngle() const
{
    return m_Angle;
}

void Point::SetX(double x)
{
    m_X = x;
    CalculateFromXY();
}

void Point::SetY(double y)
{
    m_Y = y;
    CalculateFromXY();
}

void Point::SetXY(double x, double y)
{
    m_X = x;
    m_Y = y;
    CalculateFromXY();
}

void Point::SetMag(double mag)
{
    m_Mag = mag;
    CalculateFromMagAngle();
}

void Point::SetAngle(const Angle& angle)
{
    m_Angle = angle;
    CalculateFromMagAngle();
}

Point Point::operator + (const Point& point) const
{
    Point rpoint(*this);
    rpoint+=point;
    return rpoint;
}

Point Point::operator - (const Point& point) const
{
    Point rpoint(*this);
    rpoint-=point;
    return rpoint;
}

Point Point::operator * (double value) const
{
    Point rpoint(*this);
    rpoint.SetMag(m_Mag * value);
    return rpoint;
}

void Point::operator += (const Point& point)
{
    m_X += point.m_X;
    m_Y += point.m_Y;
    CalculateFromXY();
}

void Point::operator -= (const Point& point)
{
    m_X -= point.m_X;
    m_Y -= point.m_Y;
    CalculateFromXY();
}

void Point::Sum(const Point& point, double scale)
{
    (*this) += point * scale;
}

string Point::ToString() const
{
    stringstream str;
    str << "[(" << m_X << ", " << m_Y << ")][(|" << m_Mag << "|, a<" << m_Angle.GetAngle() << ")]";
    return str.str();
}

bool Point::operator < (const Point& point) const
{
    if(m_X < point.m_X) return true;
    if(m_Y < point.m_Y && m_X == point.m_X) return true;
    return false;
}
